﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.WebSockets;
using TrayMes;
using System.Security.Policy;
using TrayCheckControl.Types;
using static System.Windows.Forms.AxHost;

namespace TrayCheckControl
{
    public partial class TrayCheckControl : UserControl
    {
        private readonly LogFileSave log = new LogFileSave();
        private readonly string envFile = "./Set/EnvironmentSet.Json";
        private WindowSet windowSet;
        private EnvironmentSet envSet = new EnvironmentSet();
        //System.Net.Sockets.Socket socketServer;
        private readonly TrayData trayData = new TrayData();
        private readonly ClientState serverState = new ClientState();
        private readonly TrayMes.TrayToMes server = new TrayMes.TrayToMes();
        public TrayCheckControl()
        {
            InitializeComponent();
            InitBindings();
            this.log.AddToLog($"{this.GetNow()}: Init Control");
        }
        public string GetNow()
        {
            return DateTime.Now.ToString("yyyyMMdd HH:mm:ss");
        }
        private void InitBindings()
        {
            Binding b;
            this.labelIdValue.DataBindings.Add(new Binding("Text", this.trayData, "Id", false, DataSourceUpdateMode.OnPropertyChanged));
            b = new Binding("BackColor", this.trayData, "IsOk", false, DataSourceUpdateMode.OnPropertyChanged, "0");
            b.Format += new ConvertEventHandler(this.JudgementToBackColor);
            this.labelIdValue.DataBindings.Add(b);
            //this.labelIdValue.DataBindings.Add(new Binding("BackColor", this.trayData, "ResultColor", false, DataSourceUpdateMode.OnPropertyChanged));
            this.labelCountValue.DataBindings.Add(new Binding("Text", this.trayData, "CountAndLimit", false, DataSourceUpdateMode.OnPropertyChanged, "0"));
            b = new Binding("ForeColor", this.trayData, "IsCountOk", false, DataSourceUpdateMode.OnPropertyChanged, "0");
            b.Format += new ConvertEventHandler(this.JudgementToColor);
            this.labelCountValue.DataBindings.Add(b);
            //this.labelCountValue.DataBindings.Add(new Binding("ForeColor", this.trayData, "ResultColor", false, DataSourceUpdateMode.OnPropertyChanged));
            this.labelPmValue.DataBindings.Add(new Binding("Text", this.trayData, "PmCurrent", false, DataSourceUpdateMode.OnPropertyChanged, "0"));
            b = new Binding("ForeColor", this.trayData, "IsPmOk", false, DataSourceUpdateMode.OnPropertyChanged, "0");
            b.Format += new ConvertEventHandler(this.JudgementToColor);
            this.labelPmValue.DataBindings.Add(b);
            //this.labelPmValue.DataBindings.Add(new Binding("ForeColor", this.trayData, "ResultColor", false, DataSourceUpdateMode.OnPropertyChanged));
            this.labelPmTypeValue.DataBindings.Add(new Binding("Text", this.trayData, "PmPeriod", false, DataSourceUpdateMode.OnPropertyChanged, "0"));
            //this.labelLockedValue.DataBindings.Add(new Binding("Text", this.trayData, "IsLocked", false, DataSourceUpdateMode.OnPropertyChanged, "0"));
            b = new Binding("ForeColor", this.trayData, "IsLocked", false, DataSourceUpdateMode.OnPropertyChanged, "0");
            b.Format += new ConvertEventHandler(this.BoolToColor);
            this.labelLockedValue.DataBindings.Add(b);
            //this.labelLockedValue.DataBindings.Add(new Binding("ForeColor", this.trayData, "ResultColor", false, DataSourceUpdateMode.OnPropertyChanged));
            b = new Binding("Text", this.serverState, "State", false, DataSourceUpdateMode.OnPropertyChanged, "0");
            b.Format += new ConvertEventHandler(this.SocketStateToString);
            this.labelServerState.DataBindings.Add(b);
            //this.labelServerState.DataBindings.Add(new Binding("Text", this.serverState, "State", false, DataSourceUpdateMode.OnPropertyChanged));
            this.pictureBoxServerState.DataBindings.Add(new Binding("Image", this.serverState, "Image", false, DataSourceUpdateMode.OnPropertyChanged));
        }
        private void SocketStateToString(object sender, ConvertEventArgs e)
        {
            if (e.DesiredType != typeof(String)) return;
            try
            {
                SocketState state = (SocketState)e.Value;
                e.Value = GetEnumDescription.GetDescriptionByEnum<DescriptionAttribute>(state).Description;
            }
            catch
            {
                e.Value = GetEnumDescription.GetDescriptionByEnum<DescriptionAttribute>(SocketState.Unknow).Description;
            }
        }
        private void JudgementToColor(object sender, ConvertEventArgs e)
        {
            if (e.DesiredType != typeof(Color)) return;
            try
            {
                switch ((Judgement)e.Value)
                {
                    case Judgement.None:
                        e.Value = System.Drawing.Color.Black;
                        break;
                    case Judgement.Fail:
                        e.Value = System.Drawing.Color.Red;
                        break;
                    case Judgement.Pass:
                        e.Value = System.Drawing.Color.DarkGreen;
                        break;
                    default:
                        e.Value = System.Drawing.Color.Yellow;
                        break;
                }
            }
            catch
            {
                e.Value = System.Drawing.Color.Yellow;
            }
        }

        private void JudgementToBackColor(object sender, ConvertEventArgs e)
        {
            if (e.DesiredType != typeof(Color)) return;
            try
            {
                switch ((Judgement)e.Value)
                {
                    case Judgement.None:
                        e.Value = System.Drawing.Color.Transparent;
                        break;
                    case Judgement.Fail:
                        e.Value = System.Drawing.Color.Red;
                        break;
                    case Judgement.Pass:
                        e.Value = System.Drawing.Color.Green;
                        break;
                    default:
                        e.Value = System.Drawing.Color.Yellow;
                        break;
                }
            }
            catch
            {
                e.Value = System.Drawing.Color.Yellow;
            }
        }
        private void BoolToColor(object sender, ConvertEventArgs e)
        {
            if (e.DesiredType != typeof(Color)) return;
            try
            {
                e.Value =
                    (bool)e.Value ? e.Value = System.Drawing.Color.Red : e.Value = System.Drawing.Color.Green;
            }
            catch
            {
                e.Value = System.Drawing.Color.Yellow;
            }
        }
        public void LoadEnvSet()
        {
            if (!System.IO.File.Exists(envFile))
            {
                this.SaveEnvSet();
            }
            string jDoc = System.IO.File.ReadAllText(envFile);
            this.envSet.Copy(Newtonsoft.Json.JsonConvert.DeserializeObject<EnvironmentSet>(jDoc));
        }
        private void SaveEnvSet(EnvironmentSet envSet)
        {
            this.envSet = envSet;
            this.SaveEnvSet();
        }
        public void SaveEnvSet()
        {
            string jDoc = Newtonsoft.Json.JsonConvert.SerializeObject(this.envSet, Newtonsoft.Json.Formatting.Indented);
            if (!System.IO.File.Exists(envFile))
            {
                System.IO.FileInfo fi = new System.IO.FileInfo(envFile);
                fi.Directory.Create();
                fi.Create().Close();
            }
            System.IO.File.WriteAllText(envFile, jDoc);
        }
        private void Button_Click(object sender, EventArgs e)
        {
            if (sender.Equals(this.buttonSet))
            {
                if (WindowSet.InstanceCount < 1)
                {
                    this.windowSet = new WindowSet();
                }
                this.windowSet.EnvSet = this.envSet;
                this.windowSet.SaveSet += new SaveSetHandler(this.SaveEnvSet);
                this.windowSet.Show();
            }
            if (sender.Equals(this.pictureBoxServerState))
            {
                this.ConnectToServer();
            }
        }
        public void ConnectToServer()
        {
            if(this.envSet.Bypass)
            {
                serverState.State = TrayMes.SocketState.Idle;
                return;
            }
            server.OnConnectStatusChanged += new TrayMes.ConnectStatusChangedHandler(this.OnSocketConnected);
            string uri = $"ws://{this.envSet.ServerSet.Ip}:{this.envSet.ServerSet.Port}";
            this.server.Open(new Uri(uri));
            this.toolTipServerState.SetToolTip(this.pictureBoxServerState, $"服务器连接中 Uri={uri}");
            this.log.AddToLog($"{this.GetNow()}: Connect to server: {uri}");
        }
        public void OnSocketConnected(object sender, TrayMes.SocketMesEventArgs e)
        {
            if(sender.Equals(this.server))
            {
                this.Invoke(new MethodInvoker(() =>
                    {
                        this.serverState.State = e.State;
                        this.ShowServerState(e);
                        
                    }));
                if (e.State == TrayMes.SocketState.Connected)
                {
                    this.log.AddToLog($"{this.GetNow()}: End connect to server: State:{e.State}; Uri:{e.Uri}; Message{e.Message}"); 
                }
                else if(e.State == TrayMes.SocketState.Opening)
                {
                    this.log.AddToLog($"{this.GetNow()}: Connect to server: State:{e.State}; Uri:{e.Uri}; Message{e.Message}");
                }
                //this.Invoke(new MethodInvoker(()=>this.ShowServerState(e)));
            }
            //System.Net.Sockets.Socket socket = (System.Net.Sockets.Socket)e.ConnectSocket;
            //if (sender.Equals(this.socketServer))
            //{
            //    try
            //    {
            //        this.Invoke(new MethodInvoker(() =>
            //        {
            //            this.serverState.IsConnected = (bool)(this.socketServer?.Connected) ? ConnectStatus.Connected : ConnectStatus.NotConnected;
            //            this.serverState.MsgSent = $"服务器连接{((bool)(this.socketServer?.Connected) ? "成功" : "失败")}";
            //            this.serverState.MsgRecv = e.RemoteEndPoint?.ToString();
            //        }));
            //        this.log.AddToLog($"{this.GetNow()}: End connect to server: {e.RemoteEndPoint?.ToString()}, Connected={(bool)(this.socketServer?.Connected)}");
            //        //this.serverConnecting = false;
            //        //this.Invoke(new MethodInvoker(this.ShowServerState));
            //    }
            //    catch(Exception ex)
            //    {
            //        System.Windows.Forms.MessageBox.Show($"{ex.Message}\n{ex.StackTrace}", "Error");
            //    }
            //}
        }
        public void ShowServerState(TrayMes.SocketMesEventArgs e)
        {
            Bitmap bitmap = Properties.Resources.ledOff;
            this.toolTipServerState.SetToolTip(this.pictureBoxServerState,
                            $"服务器连接状态:{GetEnumDescription.GetDescriptionByEnum<DescriptionAttribute>(e.State).Description}, Uri={e.Uri}");
            if (this.envSet.Bypass)
            {
                this.UpdatePictureBoxImage(this.pictureBoxServerState, Properties.Resources.Blue);
                return;
            }
            else
            {
                switch (e.State)
                {
                    case SocketState.Unknow:
                        bitmap = Properties.Resources.GrayOff;
                        break;
                    case SocketState.Uninitialized:
                        bitmap = Properties.Resources.GrayOff;
                        break;
                    case SocketState.Opening:
                        bitmap = Properties.Resources.YellowOn;
                        break;
                    case SocketState.Disconnected:
                        bitmap = Properties.Resources.RedOff;
                        break;
                    case SocketState.Connected:
                        bitmap = Properties.Resources.GreenOn;
                        break;
                    case SocketState.Idle:
                        bitmap = Properties.Resources.GreenOn;
                        break;
                    case SocketState.Buzy:
                        bitmap = Properties.Resources.YellowOn;
                        break;
                    case SocketState.Sending:
                        bitmap = Properties.Resources.YellowOn;
                        break;
                    case SocketState.Receving:
                        bitmap = Properties.Resources.YellowOn;
                        break;
                    case SocketState.Error:
                        bitmap = Properties.Resources.RedOn;
                        break;
                    default:
                        break;
                }
                this.pictureBoxServerState.Image = bitmap;
            }

            //Graphics g = pictureBoxServerState.CreateGraphics();
            //g.Clear(Color.Transparent);
            //SocketStateAttribute ssa = GetEnumDescription.GetDescriptionByEnum<SocketStateAttribute>(e.State);
            //Color color = Color.FromName(ssa.Background);
            //g.FillEllipse(new SolidBrush(color), this.pictureBoxServerState.DisplayRectangle);
            //color = Color.FromName(ssa.Foreground);
            //g.DrawEllipse(new Pen(color,1), this.pictureBoxServerState.DisplayRectangle);
            //g.DrawString(ssa.Context,
            //    this.labelTrayId.Font,
            //    new SolidBrush(color),
            //    this.pictureBoxServerState.DisplayRectangle);
            //this.pictureBoxServerState.Update();
            //if (this.socketServer.Connected)
            //{
            //    this.UpdatePictureBoxImage(this.pictureBoxServerState, Properties.Resources.ledOn);
            //    this.UpdateControlText(this.labelServerState, "已连接");
            //}
            //else
            //{
            //    this.UpdatePictureBoxImage(this.pictureBoxServerState, Properties.Resources.ledOff);
            //    this.UpdateControlText(this.labelServerState, "未连接");
            //}
        }
        public ErrorCodeSocket CheckTray(string id, out int remainedValue)
        {
            return this.CheckTray(new TrayData() { Id = id }, out remainedValue);
        }
        public ErrorCodeSocket CheckTray(TrayData trayData, out int remainedValue)
        {
            string tmpMsg = $"{this.GetNow()}: Begin Check Tray: Id={trayData.Id}";
            string msg = tmpMsg;
            remainedValue = -1;
            if(envSet.Bypass)
            {
                remainedValue = 10;
                this.trayData.Id = trayData.Id;
                this.log.AddToLog($"Tray Check is bypassed, return default value 10.");
                this.toolTipServerState.SetToolTip(this.pictureBoxServerState, "已禁用检查");
                this.toolTipServerState.SetToolTip(this.pictureBoxServerState, msg);
                return ErrorCodeSocket.Bypass;
            }
            this.log.AddToLog(tmpMsg);
            ErrorCodeSocket errCode = ErrorCodeSocket.NotProcessed;
            //this.InitTrayCheckResult();
            //if (trayData.Id == this.trayData.Id)
            //{
            //    trayData.Copy(this.trayData);
            //    remainedValue = trayData.CountCurrent > 0 ? trayData.CountLimit - trayData.CountCurrent : 0;
            //    tmpMsg = $"托未变化，使用上次信息, RemainTimes: {remainedValue}";
            //    msg += $"\n{this.GetNow()}: {tmpMsg}";
            //    this.log.AddToLog(tmpMsg);
            //    this.toolTipServerState.SetToolTip(this.pictureBoxServerState, msg);
            //    return ErrorCodeSocket.Success;
            //}
            this.trayData.Id = trayData.Id;
            //this.labelId.Text = trayData.Id;
            if (string.IsNullOrEmpty(trayData.Id))
            {
                tmpMsg = $"无效ID(值为空)";
                msg += $"\n{this.GetNow()}: {tmpMsg}";
                //this.UpdateControlText(this.labelServerMsgSent, "Invalid ID(empty or null)");
                errCode = ErrorCodeSocket.InvalidId;
                this.log.AddToLog(tmpMsg);
                this.ShowServerState(new SocketMesEventArgs()
                {
                    Uri = $"ws://{this.envSet.ServerSet.Ip}:{this.envSet.ServerSet.Port}",
                    State = this.serverState.State, 
                    Message = ""
                });
                this.toolTipServerState.SetToolTip(this.pictureBoxServerState, msg);
                return errCode;
            }
            if (this.server.State != System.Net.WebSockets.WebSocketState.Open)
            {
                //this.trayData.RemainTimes = 0;
                tmpMsg = $"未连接到服务器";
                msg += $"\n{this.GetNow()}: {tmpMsg}";
                this.serverState.State = this.server.State == System.Net.WebSockets.WebSocketState.Connecting ? 
                    SocketState.Opening : SocketState.Disconnected;
                //this.OnSocketConnected(this.socketServer,
                //    new SocketMesEventArgs()
                //    {
                //        State = TrayMes.SocketState.Connected,
                //        Message = "未连接到服务器",
                //    });
                this.ShowServerState(new SocketMesEventArgs()
                {
                    Uri = $"ws://{this.envSet.ServerSet.Ip}:{this.envSet.ServerSet.Port}",
                    State = this.serverState.State, 
                    Message = ""
                });
                this.log.AddToLog(tmpMsg);
                //this.UpdatePictureBoxImage(this.pictureBoxServerState, Properties.Resources.ledOff);
                //this.UpdateControlText(this.labelServerState, "未连接");
                //this.UpdateControlText(this.labelServerMsgSent, "Server is not Connected");
                errCode = ErrorCodeSocket.NotConnected;
                //this.ShowTrayCheckResult(remainedValue);
                this.toolTipServerState.SetToolTip(this.pictureBoxServerState, msg);
                return errCode;
            }
            try
            {
                this.server.Seperators = new string[] { this.envSet.CarrierSet.Seperator };
                trayData.CountCurrent = this.server.GetPalletCountValue(trayData.Id, envSet.CarrierSet.IdType);
                tmpMsg = "Query Count Value:";
                for (int i = 0; i < this.server.MessageRS.Length; i++)
                {
                    tmpMsg += $"\n{server.MessageRS[i]}";
                }
                this.log.AddToLog(tmpMsg);
                msg += $"\n{this.GetNow()}: {tmpMsg}";
                trayData.CountLimit = this.server.GetPalletCountLimit(envSet.CarrierSet.Station,
                    TrayMes.GetEnumDescription.GetDescriptionByEnum<DescriptionAttribute>(Operation.CountLimit).Description);
                tmpMsg = "Query Count Limit:";
                for (int i = 0; i < this.server.MessageRS.Length; i++)
                {
                    tmpMsg += $"\n{server.MessageRS[i]}";
                }
                this.log.AddToLog(tmpMsg);
                msg += $"\n{this.GetNow()}: {tmpMsg}";
                trayData.PmCurrent = this.server.GetPalletPmValue(trayData.Id, envSet.CarrierSet.IdType);
                tmpMsg = "Query PM Value:";
                for (int i = 0; i < this.server.MessageRS.Length; i++)
                {
                    tmpMsg += $"\n{server.MessageRS[i]}";
                }
                this.log.AddToLog(tmpMsg);
                msg += $"\n{this.GetNow()}: {tmpMsg}";
                trayData.PmPeriod = this.server.GetPalletPmPeriod(envSet.CarrierSet.Station,
                    TrayMes.GetEnumDescription.GetDescriptionByEnum<DescriptionAttribute>(Operation.PmCycle).Description);
                tmpMsg = "Query PM Period:";
                for (int i = 0; i < this.server.MessageRS.Length; i++)
                {
                    tmpMsg += $"\n{server.MessageRS[i]}";
                }
                this.log.AddToLog(tmpMsg);
                msg += $"\n{this.GetNow()}: {tmpMsg}";
                //this.server.GetPalletCountValue("cs-load", "isLock");
                //tmpMsg = "Query Is Locked:";
                //for (int i = 0; i < this.server.MessageRS.Length; i++)
                //{
                //    tmpMsg += $"\n{server.MessageRS[i]}";
                //}
                //this.log.AddToLog(tmpMsg);
                //msg += $"{this.GetNow()}: \n{tmpMsg}";
                trayData.Judge();
                this.trayData.Copy(trayData);
                this.trayData.Judge();
                errCode = ErrorCodeSocket.Success;
                //MessageBox.Show($"C:{trayData.CountCurrent};L:{trayData.CountLimit}\nC/L:{trayData.CountAndLimit}\nP:{trayData.PmCurrent};PP:{trayData.PmPeriod}");
            }
            catch(Exception ex)
            {
                this.serverState.State = TrayMes.SocketState.Error;
                tmpMsg = $"查询状态时发生错误: {ex.Message}";
                msg += $"\n{this.GetNow()}: \n{tmpMsg}";
                this.log.AddToLog(tmpMsg);
                //this.UpdatePictureBoxImage(this.pictureBoxServerState, Properties.Resources.ledOff);
                //this.UpdateControlText(this.labelServerState, "未连接");
                errCode = ErrorCodeSocket.ErrorSend;
                //this.ShowTrayCheckResult(remainedValue);
            }
            this.toolTipServerState.SetToolTip(this.pictureBoxServerState, msg);
            remainedValue = Judgement.Pass == trayData.IsOk ? trayData.CountLimit-trayData.CountCurrent: 0;
            return errCode;
        }
        public void InitTrayCheckResult()
        {
            this.UpdateControlText(this.labelIdValue, string.Empty);
            this.UpdateControlBackColor(labelIdValue, Color.Transparent);
            this.UpdateControlText(this.labelCountValue, string.Empty);
            this.UpdateControlForeColor(labelIdValue, Color.Transparent);
            this.UpdateControlText(this.labelPmValue, string.Empty);
            this.UpdateControlForeColor(this.labelPmValue, Color.Transparent);
            this.UpdateControlText(this.labelLockedValue, string.Empty);
            this.UpdateControlForeColor(this.labelLockedValue, Color.Transparent);
        }
        public void UpdateControlText(Control control, string value)
        {
            if(control.InvokeRequired)
            {
                this.Invoke(new MethodInvoker(() => { control.Text = value; }));
            }
            else
            {
                control.Text = value;
            }
        }
        public void UpdateControlBackColor(Control control, Color value)
        {
            if(control.InvokeRequired)
            {
                this.Invoke(new MethodInvoker(() => { control.BackColor = value; }));
            }
            else
            {
                control.BackColor = value;
            }
        }
        public void UpdateControlForeColor(Control control, Color value)
        {
            if(control.InvokeRequired)
            {
                this.Invoke(new MethodInvoker(() => { control.ForeColor = value; }));
            }
            else
            {
                control.BackColor = value;
            }
        }
        public void UpdatePictureBoxImage(PictureBox pictureBox, Image value)
        {
            if(pictureBox.InvokeRequired)
            {
                this.Invoke(new MethodInvoker(() => { pictureBox.Image = value; }));
            }
            else
            {
                pictureBox.Image = value;
            }
        }
        public void ShowTrayCheckResult(int remainValue)
        {
            this.UpdateControlText(this.labelCount, $"剩余:{remainValue}");
            if (remainValue>0)
            {
                if(remainValue>1)
                {
                    this.UpdateControlBackColor(labelIdValue, Color.SpringGreen);
                }
                else
                {
                    this.UpdateControlBackColor(labelIdValue, Color.Orange);
                }
            }
            else
            {
                this.UpdateControlBackColor(labelIdValue, Color.Red);
            }
        }

        public void Control_Load(object sender, EventArgs e)
        {
            this.LoadEnvSet();
            this.ConnectToServer();
        }
        public void Init()
        {
            this.LoadEnvSet();
            this.ConnectToServer();
        }

        private void Label_DClick(object sender, EventArgs e)
        {
            if(sender.Equals(this.labelIdValue))
            {
                this.trayData.Id = string.Empty;
                this.log.AddToLog($"托盘信息已初始化");
            }
        }
        public void Close()
        {
            this.log.Close();
        }
        public new void Dispose()
        {
            this.Close();
            base.Dispose();
        }
    }
}
